home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 60 / IOPROG_60.ISO / soft / c++ / gsl-1.1.1-setup.exe / {app} / src / linalg / svd.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-04-18  |  14.8 KB  |  584 lines

  1. /* linalg/svd.c
  2.  * 
  3.  * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman, Brian Gough
  4.  * 
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or (at
  8.  * your option) any later version.
  9.  * 
  10.  * This program is distributed in the hope that it will be useful, but
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #include <config.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <gsl/gsl_math.h>
  24. #include <gsl/gsl_vector.h>
  25. #include <gsl/gsl_matrix.h>
  26. #include <gsl/gsl_blas.h>
  27.  
  28. #include <gsl/gsl_linalg.h>
  29.  
  30. #include "givens.c"
  31. #include "svdstep.c"
  32.  
  33. /* Factorise a general M x N matrix A into,
  34.  *
  35.  *   A = U D V^T
  36.  *
  37.  * where U is a column-orthogonal M x N matrix (U^T U = I), 
  38.  * D is a diagonal N x N matrix, 
  39.  * and V is an N x N orthogonal matrix (V^T V = V V^T = I)
  40.  *
  41.  * U is stored in the original matrix A, which has the same size
  42.  *
  43.  * V is stored as a separate matrix (not V^T). You must take the
  44.  * transpose to form the product above.
  45.  *
  46.  * The diagonal matrix D is stored in the vector S,  D_ii = S_i
  47.  */
  48.  
  49. int
  50. gsl_linalg_SV_decomp (gsl_matrix * A, gsl_matrix * V, gsl_vector * S, 
  51.                       gsl_vector * work)
  52. {
  53.   size_t a, b, i, j;
  54.  
  55.   const size_t M = A->size1;
  56.   const size_t N = A->size2;
  57.   const size_t K = GSL_MIN (M, N);
  58.  
  59.   if (M < N)
  60.     {
  61.       GSL_ERROR ("svd of MxN matrix, M<N, is not implemented", GSL_EUNIMPL);
  62.     }
  63.   else if (V->size1 != N)
  64.     {
  65.       GSL_ERROR ("square matrix V must match second dimension of matrix A",
  66.          GSL_EBADLEN);
  67.     }
  68.   else if (V->size1 != V->size2)
  69.     {
  70.       GSL_ERROR ("matrix V must be square", GSL_ENOTSQR);
  71.     }
  72.   else if (S->size != N)
  73.     {
  74.       GSL_ERROR ("length of vector S must match second dimension of matrix A",
  75.          GSL_EBADLEN);
  76.     }
  77.   else if (work->size != N)
  78.     {
  79.       GSL_ERROR ("length of workspace must match second dimension of matrix A",
  80.          GSL_EBADLEN);
  81.     }
  82.  
  83.   
  84.   {
  85.     gsl_vector_view f = gsl_vector_subvector (work, 0, K - 1);
  86.     
  87.     /* bidiagonalize matrix A, unpack A into U V S */
  88.     
  89.     gsl_linalg_bidiag_decomp (A, S, &f.vector);
  90.     gsl_linalg_bidiag_unpack2 (A, S, &f.vector, V);
  91.     
  92.     /* apply reduction steps to B=(S,Sd) */
  93.     
  94.     chop_small_elements (S, &f.vector);
  95.     
  96.     /* Progressively reduce the matrix until it is diagonal */
  97.     
  98.     b = N - 1;
  99.     
  100.     while (b > 0)
  101.       {
  102.         if (gsl_vector_get (&f.vector, b - 1) == 0.0)
  103.           {
  104.             b--;
  105.             continue;
  106.           }
  107.         
  108.         /* Find the largest unreduced block (a,b) starting from b
  109.            and working backwards */
  110.         
  111.         a = b - 1;
  112.         
  113.         while (a > 0)
  114.           {
  115.             if (gsl_vector_get (&f.vector, a - 1) == 0.0)
  116.               {
  117.                 break;
  118.               }
  119.             
  120.             a--;
  121.           }
  122.         
  123.         {
  124.           const size_t n_block = b - a + 1;
  125.           gsl_vector_view S_block = gsl_vector_subvector (S, a, n_block);
  126.           gsl_vector_view f_block = gsl_vector_subvector (&f.vector, a, n_block - 1);
  127.           
  128.           gsl_matrix_view U_block =
  129.             gsl_matrix_submatrix (A, 0, a, A->size1, n_block);
  130.           gsl_matrix_view V_block =
  131.             gsl_matrix_submatrix (V, 0, a, V->size1, n_block);
  132.           
  133.           qrstep (&S_block.vector, &f_block.vector, &U_block.matrix, &V_block.matrix);
  134.           
  135.           /* remove any small off-diagonal elements */
  136.           
  137.           chop_small_elements (&S_block.vector, &f_block.vector);
  138.         }
  139.       }
  140.   }
  141.   /* Make singular values positive by reflections if necessary */
  142.   
  143.   for (j = 0; j < K; j++)
  144.     {
  145.       double Sj = gsl_vector_get (S, j);
  146.       
  147.       if (Sj < 0.0)
  148.         {
  149.           for (i = 0; i < N; i++)
  150.             {
  151.               double Vij = gsl_matrix_get (V, i, j);
  152.               gsl_matrix_set (V, i, j, -Vij);
  153.             }
  154.           
  155.           gsl_vector_set (S, j, -Sj);
  156.         }
  157.     }
  158.   
  159.   /* Sort singular values into decreasing order */
  160.   
  161.   for (i = 0; i < K; i++)
  162.     {
  163.       double Si = gsl_vector_get (S, i);
  164.       size_t i_max = i;
  165.       
  166.       for (j = i + 1; j < K; j++)
  167.         {
  168.           double Sj = gsl_vector_get (S, j);
  169.           
  170.           if (Sj > Si)
  171.             {
  172.           i_max = j;
  173.         }
  174.     }
  175.       
  176.       if (i_max != i)
  177.     {
  178.       /* swap eigenvalues */
  179.       gsl_vector_swap_elements (S, i, i_max);
  180.           
  181.       /* swap eigenvectors */
  182.       gsl_matrix_swap_columns (A, i, i_max);
  183.       gsl_matrix_swap_columns (V, i, i_max);
  184.     }
  185.     }
  186.   
  187.   return GSL_SUCCESS;
  188. }
  189.  
  190.  
  191. /* Modified algorithm which is better for M>>N */
  192.  
  193. int
  194. gsl_linalg_SV_decomp_mod (gsl_matrix * A,
  195.               gsl_matrix * X,
  196.               gsl_matrix * V, gsl_vector * S, gsl_vector * work)
  197. {
  198.   size_t i, j;
  199.  
  200.   const size_t M = A->size1;
  201.   const size_t N = A->size2;
  202.  
  203.   if (M < N)
  204.     {
  205.       GSL_ERROR ("svd of MxN matrix, M<N, is not implemented", GSL_EUNIMPL);
  206.     }
  207.   else if (V->size1 != N)
  208.     {
  209.       GSL_ERROR ("square matrix V must match second dimension of matrix A",
  210.          GSL_EBADLEN);
  211.     }
  212.   else if (V->size1 != V->size2)
  213.     {
  214.       GSL_ERROR ("matrix V must be square", GSL_ENOTSQR);
  215.     }
  216.   else if (X->size1 != N)
  217.     {
  218.       GSL_ERROR ("square matrix X must match second dimension of matrix A",
  219.          GSL_EBADLEN);
  220.     }
  221.   else if (X->size1 != X->size2)
  222.     {
  223.       GSL_ERROR ("matrix X must be square", GSL_ENOTSQR);
  224.     }
  225.   else if (S->size != N)
  226.     {
  227.       GSL_ERROR ("length of vector S must match second dimension of matrix A",
  228.          GSL_EBADLEN);
  229.     }
  230.   else if (work->size != N)
  231.     {
  232.       GSL_ERROR ("length of workspace must match second dimension of matrix A",
  233.          GSL_EBADLEN);
  234.     }
  235.  
  236.   /* Convert A into an upper triangular matrix R */
  237.  
  238.   for (i = 0; i < N; i++)
  239.     {
  240.       gsl_vector_view c = gsl_matrix_column (A, i);
  241.       gsl_vector_view v = gsl_vector_subvector (&c.vector, i, M - i);
  242.       double tau_i = gsl_linalg_householder_transform (&v.vector);
  243.  
  244.       /* Apply the transformation to the remaining columns */
  245.  
  246.       if (i + 1 < N)
  247.     {
  248.       gsl_matrix_view m =
  249.         gsl_matrix_submatrix (A, i, i + 1, M - i, N - (i + 1));
  250.       gsl_linalg_householder_hm (tau_i, &v.vector, &m.matrix);
  251.     }
  252.  
  253.       gsl_vector_set (S, i, tau_i);
  254.     }
  255.  
  256.   /* Copy the upper triangular part of A into X */
  257.  
  258.   for (i = 0; i < N; i++)
  259.     {
  260.       for (j = 0; j < i; j++)
  261.     {
  262.       gsl_matrix_set (X, i, j, 0.0);
  263.     }
  264.  
  265.       {
  266.     double Aii = gsl_matrix_get (A, i, i);
  267.     gsl_matrix_set (X, i, i, Aii);
  268.       }
  269.  
  270.       for (j = i + 1; j < N; j++)
  271.     {
  272.       double Aij = gsl_matrix_get (A, i, j);
  273.       gsl_matrix_set (X, i, j, Aij);
  274.     }
  275.     }
  276.  
  277.   /* Convert A into an orthogonal matrix L */
  278.  
  279.   for (j = N; j > 0 && j--;)
  280.     {
  281.       /* Householder column transformation to accumulate L */
  282.       double tj = gsl_vector_get (S, j);
  283.       gsl_matrix_view m = gsl_matrix_submatrix (A, j, j, M - j, N - j);
  284.       gsl_linalg_householder_hm1 (tj, &m.matrix);
  285.     }
  286.  
  287.   /* unpack R into X V S */
  288.  
  289.   gsl_linalg_SV_decomp (X, V, S, work);
  290.  
  291.   /* Multiply L by X, to obtain U = L X, stored in U */
  292.  
  293.   {
  294.     gsl_vector_view sum = gsl_vector_subvector (work, 0, N);
  295.  
  296.     for (i = 0; i < M; i++)
  297.       {
  298.     gsl_vector_view L_i = gsl_matrix_row (A, i);
  299.     gsl_vector_set_zero (&sum.vector);
  300.  
  301.     for (j = 0; j < N; j++)
  302.       {
  303.         double Lij = gsl_vector_get (&L_i.vector, j);
  304.         gsl_vector_view X_j = gsl_matrix_row (X, j);
  305.         gsl_blas_daxpy (Lij, &X_j.vector, &sum.vector);
  306.       }
  307.  
  308.     gsl_vector_memcpy (&L_i.vector, &sum.vector);
  309.       }
  310.   }
  311.  
  312.   return GSL_SUCCESS;
  313. }
  314.  
  315.  
  316. /*  Solves the system A x = b using the SVD factorization
  317.  *
  318.  *  A = U S V^T
  319.  *
  320.  *  to obtain x. For M x N systems it finds the solution in the least
  321.  *  squares sense.  
  322.  */
  323.  
  324. int
  325. gsl_linalg_SV_solve (const gsl_matrix * U,
  326.              const gsl_matrix * V,
  327.              const gsl_vector * S,
  328.              const gsl_vector * b, gsl_vector * x)
  329. {
  330.   if (U->size1 != b->size)
  331.     {
  332.       GSL_ERROR ("first dimension of matrix U must size of vector b",
  333.          GSL_EBADLEN);
  334.     }
  335.   else if (U->size2 != S->size)
  336.     {
  337.       GSL_ERROR ("length of vector S must match second dimension of matrix U",
  338.          GSL_EBADLEN);
  339.     }
  340.   else if (V->size1 != V->size2)
  341.     {
  342.       GSL_ERROR ("matrix V must be square", GSL_ENOTSQR);
  343.     }
  344.   else if (S->size != V->size1)
  345.     {
  346.       GSL_ERROR ("length of vector S must match size of matrix V",
  347.          GSL_EBADLEN);
  348.     }
  349.   else if (V->size2 != x->size)
  350.     {
  351.       GSL_ERROR ("size of matrix V must match size of vector x", GSL_EBADLEN);
  352.     }
  353.   else
  354.     {
  355.       const size_t N = U->size2;
  356.       size_t i;
  357.  
  358.       gsl_vector *w = gsl_vector_calloc (N);
  359.  
  360.       gsl_blas_dgemv (CblasTrans, 1.0, U, b, 0.0, w);
  361.  
  362.       for (i = 0; i < N; i++)
  363.     {
  364.       double wi = gsl_vector_get (w, i);
  365.       double alpha = gsl_vector_get (S, i);
  366.       if (alpha != 0)
  367.         alpha = 1.0 / alpha;
  368.       gsl_vector_set (w, i, alpha * wi);
  369.     }
  370.  
  371.       gsl_blas_dgemv (CblasNoTrans, 1.0, V, w, 0.0, x);
  372.  
  373.       gsl_vector_free (w);
  374.  
  375.       return GSL_SUCCESS;
  376.     }
  377. }
  378.  
  379. /* This is a the jacobi version */
  380. /* Author:  G. Jungman */
  381.  
  382. /*
  383.  * Algorithm due to J.C. Nash, Compact Numerical Methods for
  384.  * Computers (New York: Wiley and Sons, 1979), chapter 3.
  385.  * See also Algorithm 4.1 in
  386.  * James Demmel, Kresimir Veselic, "Jacobi's Method is more
  387.  * accurate than QR", Lapack Working Note 15 (LAWN15), October 1989.
  388.  * Available from netlib.
  389.  *
  390.  * Based on code by Arthur Kosowsky, Rutgers University
  391.  *                  kosowsky@physics.rutgers.edu  
  392.  *
  393.  * Another relevant paper is, P.P.M. De Rijk, "A One-Sided Jacobi
  394.  * Algorithm for computing the singular value decomposition on a
  395.  * vector computer", SIAM Journal of Scientific and Statistical
  396.  * Computing, Vol 10, No 2, pp 359-371, March 1989.
  397.  * 
  398.  */
  399.  
  400. int
  401. gsl_linalg_SV_decomp_jacobi (gsl_matrix * A, gsl_matrix * Q, gsl_vector * S)
  402. {
  403.   if (Q->size1 < Q->size2)
  404.     {
  405.       /* FIXME: only implemented  M>=N case so far */
  406.  
  407.       GSL_ERROR ("svd of MxN matrix, M<N, is not implemented", GSL_EUNIMPL);
  408.     }
  409.   else if (Q->size1 != A->size2)
  410.     {
  411.       GSL_ERROR ("square matrix Q must match second dimension of matrix A",
  412.          GSL_EBADLEN);
  413.     }
  414.   else if (Q->size1 != Q->size2)
  415.     {
  416.       GSL_ERROR ("matrix Q must be square", GSL_ENOTSQR);
  417.     }
  418.   else if (S->size != A->size2)
  419.     {
  420.       GSL_ERROR ("length of vector S must match second dimension of matrix A",
  421.          GSL_EBADLEN);
  422.     }
  423.   else
  424.     {
  425.       const size_t M = A->size1;
  426.       const size_t N = A->size2;
  427.       size_t i, j, k;
  428.  
  429.       /* Initialize the rotation counter and the sweep counter. */
  430.       int count = 1;
  431.       int sweep = 0;
  432.       int sweepmax = N;
  433.  
  434.       double tolerance = 10 * GSL_DBL_EPSILON;
  435.  
  436.       /* Always do at least 12 sweeps. */
  437.       sweepmax = GSL_MAX (sweepmax, 12);
  438.  
  439.       /* Set Q to the identity matrix. */
  440.       gsl_matrix_set_identity (Q);
  441.  
  442.       /* Orthogonalize A by plane rotations. */
  443.  
  444.       while (count > 0 && sweep <= sweepmax)
  445.     {
  446.       /* Initialize rotation counter. */
  447.       count = N * (N - 1) / 2;
  448.  
  449.       for (j = 0; j < N - 1; j++)
  450.         {
  451.           for (k = j + 1; k < N; k++)
  452.         {
  453.           double a = 0.0;
  454.           double b = 0.0;
  455.           double p = 0.0;
  456.           double q = 0.0;
  457.           double r = 0.0;
  458.           double cosine, sine;
  459.           double v;
  460.  
  461.           gsl_vector_view cj = gsl_matrix_column (A, j);
  462.           gsl_vector_view ck = gsl_matrix_column (A, k);
  463.  
  464.           gsl_blas_ddot (&cj.vector, &ck.vector, &p);
  465.  
  466.           a = gsl_blas_dnrm2 (&cj.vector);
  467.           b = gsl_blas_dnrm2 (&ck.vector);
  468.  
  469.           q = a * a;
  470.           r = b * b;
  471.  
  472.           /* NOTE: this could be handled better by scaling
  473.            * the calculation of the inner products above.
  474.            * But I'm too lazy. This will have to do. [GJ]
  475.            */
  476.  
  477.           /* FIXME: This routine is a hack. We need to get the
  478.              state of the art in Jacobi SVD's here ! */
  479.  
  480.           /* This is an adhoc method of testing for a "zero"
  481.              singular value. We consider it to be zero if it
  482.              is sufficiently small compared with the currently
  483.              leading column. Note that b <= a is guaranteed by
  484.              the sweeping algorithm. BJG */
  485.  
  486.           if (b <= tolerance * a)
  487.             {
  488.               /* probably |b| = 0 */
  489.               count--;
  490.               continue;
  491.             }
  492.  
  493.           if (fabs (p) <= tolerance * a * b)
  494.             {
  495.               /* columns j,k orthogonal
  496.                * note that p*p/(q*r) is automatically <= 1.0
  497.                */
  498.               count--;
  499.               continue;
  500.             }
  501.  
  502.           /* calculate rotation angles */
  503.           if (q < r)
  504.             {
  505.               cosine = 0.0;
  506.               sine = 1.0;
  507.             }
  508.           else
  509.             {
  510.               q -= r;
  511.               v = hypot (2.0 * p, q);
  512.               cosine = sqrt ((v + q) / (2.0 * v));
  513.               sine = p / (v * cosine);
  514.             }
  515.  
  516.           /* apply rotation to A */
  517.           for (i = 0; i < M; i++)
  518.             {
  519.               const double Aik = gsl_matrix_get (A, i, k);
  520.               const double Aij = gsl_matrix_get (A, i, j);
  521.               gsl_matrix_set (A, i, j, Aij * cosine + Aik * sine);
  522.               gsl_matrix_set (A, i, k, -Aij * sine + Aik * cosine);
  523.             }
  524.  
  525.           /* apply rotation to Q */
  526.           for (i = 0; i < N; i++)
  527.             {
  528.               const double Qij = gsl_matrix_get (Q, i, j);
  529.               const double Qik = gsl_matrix_get (Q, i, k);
  530.               gsl_matrix_set (Q, i, j, Qij * cosine + Qik * sine);
  531.               gsl_matrix_set (Q, i, k, -Qij * sine + Qik * cosine);
  532.             }
  533.         }
  534.         }
  535.  
  536.       /* Sweep completed. */
  537.       sweep++;
  538.     }
  539.  
  540.       /* 
  541.        * Orthogonalization complete. Compute singular values.
  542.        */
  543.  
  544.       {
  545.     double prev_norm = -1.0;
  546.  
  547.     for (j = 0; j < N; j++)
  548.       {
  549.         gsl_vector_view column = gsl_matrix_column (A, j);
  550.         double norm = gsl_blas_dnrm2 (&column.vector);
  551.  
  552.         /* Determine if singular value is zero, according to the
  553.            criteria used in the main loop above (i.e. comparison
  554.            with norm of previous column). */
  555.  
  556.         if (norm == 0.0 || prev_norm == 0.0 
  557.                 || (j > 0 && norm <= tolerance * prev_norm))
  558.           {
  559.         gsl_vector_set (S, j, 0.0);    /* singular */
  560.         gsl_vector_set_zero (&column.vector);    /* annihilate column */
  561.  
  562.         prev_norm = 0.0;
  563.           }
  564.         else
  565.           {
  566.         gsl_vector_set (S, j, norm);    /* non-singular */
  567.         gsl_vector_scale (&column.vector, 1.0 / norm);    /* normalize column */
  568.  
  569.         prev_norm = norm;
  570.           }
  571.       }
  572.       }
  573.  
  574.       if (count > 0)
  575.     {
  576.       /* reached sweep limit */
  577.       GSL_ERROR ("Jacobi iterations did not reach desired tolerance",
  578.              GSL_ETOL);
  579.     }
  580.  
  581.       return GSL_SUCCESS;
  582.     }
  583. }
  584.